﻿Imports System.IO
Imports System.Runtime.CompilerServices

Namespace OldVersion

	Module Module1

		Dim SourcePath As String = "C:\Downloads\FIX\Repository\FIX.4.4"
		Dim TargetPath As String = Path.Combine("C:\Source\Prototypes - Not for Production\Fix Engine Rewrite\Scratch", "Generated")

		Dim EnumsXml As XDocument = XDocument.Load(Path.Combine(SourcePath, "Enums.xml"))
		Dim MsgTypeXml As XDocument = XDocument.Load(Path.Combine(SourcePath, "MsgType.xml"))
		Dim MsgContentsXml As XDocument = XDocument.Load(Path.Combine(SourcePath, "MsgContents.xml"))
		Dim ComponentsXml As XDocument = XDocument.Load(Path.Combine(SourcePath, "Components.xml"))
		Dim FieldsXml As XDocument = XDocument.Load(Path.Combine(SourcePath, "Fields.xml"))

		Dim MessageContents As New List(Of MessageContent)
		Dim TagFieldMap As New Dictionary(Of Integer, String)
		Dim TagPropertyMap As New Dictionary(Of Integer, String)
		'Dim TagPropertyMapRequired As Dictionary(Of Integer, String) = TagPropertyMap
		'Dim TagPropertyMapRequired As New Dictionary(Of Integer, String)

		Sub Main()
			If Directory.Exists(TargetPath) Then Directory.Delete(TargetPath, True)
			Directory.CreateDirectory(TargetPath)

			ParseFieldsFile()
			ParseMessageContentsFile()

			CreateMessages()


			'this is only used for testing
			Dim scratch As New Text.StringBuilder
			scratch.AppendLine("Class FieldTest")
			For Each fragment In TagPropertyMap.Values
				scratch.AppendLine(fragment)
			Next
			scratch.AppendLine("End Class ")
			File.WriteAllText(Path.Combine(TargetPath, "FieldTest.vb"), scratch.ToString)


		End Sub


		Private Sub ParseFieldsFile()
			For Each item In FieldsXml.<dataroot>.<Fields>

				Dim propName As String = item.<FieldName>.Value.ToIdentifier
				If propName = "" Then Continue For

				Dim fieldNumber = CInt(item.<Tag>.Value)

				TagFieldMap.Add(fieldNumber, propName)

				Dim attributes As String = ""

				If item.<FieldName>.Value.ToLower.Contains("(no longer used)") Then
					attributes = "<Obsolete()>"
				End If

				Dim propType = item.<Type>.Value


				Dim fragment = _
				"Private m_" & propName & " As String" & vbCrLf & _
				 vbCrLf & _
				"''' <summary>" & vbCrLf & _
				"''' " & item.<FieldName>.Value & " (" & fieldNumber & ")" & vbCrLf & _
				"''' " & item.<Desc>.Value.ToCommentFormat & vbCrLf & _
				"''' </summary>" & vbCrLf & _
				"''' <value></value>" & vbCrLf & _
				"''' <returns></returns>" & vbCrLf & _
				"''' <remarks></remarks>" & vbCrLf & _
				attributes & " Public Property " & propName & "() As String" & vbCrLf & _
				"    Get" & vbCrLf & _
				"        Return m_" & propName & vbCrLf & _
				"    End Get" & vbCrLf & _
				"    Set(ByVal value As String)" & vbCrLf & _
				"        m_" & propName & " = value" & vbCrLf & _
				"    End Set" & vbCrLf & _
				"End Property" & vbCrLf

				TagPropertyMap.Add(fieldNumber, fragment)

			Next
		End Sub

		<Extension()> Private Function NormalizeLineEndings(ByVal this As String) As String
			Return this.Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, vbCrLf)
		End Function

		<Extension()> Private Function StripLineEndings(ByVal this As String) As String
			Return this.Replace(vbCrLf, "").Replace(vbLf, "").Replace(vbCr, "")
		End Function

		<Extension()> Private Function ToCommentFormat(ByVal this As String) As String
			Dim result As String

			result = this.NormalizeLineEndings

			'remove double line breaks
			'result = result.Replace(vbCrLf & vbCrLf, vbCrLf)

			'trim both ends
			result = result.Trim

			'don't allow embedded angle brackets
			result = result.Replace("<", "&lt;").Replace(">", "&gt;")

			'add prefix for comments
			result = result.Replace(vbCrLf, vbCrLf & "'''")

			Return result

		End Function

		<Extension()> Private Function ToIdentifier(ByVal this As String) As String
			Dim result As String

			result = this

			'remove any notes after the name
			If result.Contains("(") Then
				result = result.Substring(0, result.IndexOf("("))
			End If

			result = result.Replace("-", "").Replace("_", "").Replace("/", "").Trim

			If result.Contains(" ") Then
				Dim parts = result.Split(" "c)
				For i = 0 To parts.Length - 1
					If parts(i).Length > 1 Then
						parts(i) = parts(i).Substring(0, 1).ToUpper & parts(i).Substring(1)
					End If
				Next
				result = String.Join("", parts)
			End If

			Return result
		End Function



		Private Sub CreateMessages()

			Dim base = <s>
Public MustInherit Class Message
    Public MustOverride Readonly Property MessageName as String
    Public MustOverride Readonly Property MessageType as String
    Public MustOverride Readonly Property MessageId as Integer
    Public MustOverride Readonly Property Category as String
    Public MustOverride Readonly Property Section as String
End Class
                   </s>.Value

			File.WriteAllText(Path.Combine(TargetPath, "Message.vb"), base)

			Directory.CreateDirectory(TargetPath & "\Messages")

			For Each item In MsgTypeXml.<dataroot>.<MsgType>
				Dim msgClass = <s>
    		Public Class <%= item.<MessageName>.Value.ToIdentifier %>
    		    Inherits Message

    		    Public Overrides ReadOnly Property Category() As String
    		        Get
    		            Return "<%= item.<Category>.Value %>"
    		        End Get
    		    End Property

    		    Public Overrides ReadOnly Property MessageId() As Integer
    		        Get
    		            Return <%= item.<MsgID>.Value %>
    		        End Get
    		    End Property

    		    Public Overrides ReadOnly Property MessageName() As String
    		        Get
    		            Return "<%= item.<MessageName>.Value %>"
    		        End Get
    		    End Property

    		    Public Overrides ReadOnly Property MessageType() As String
    		        Get
    		            Return "<%= item.<MsgType>.Value %>"
    		        End Get
    		    End Property

    		    Public Overrides ReadOnly Property Section() As String
    		        Get
    		            Return "<%= item.<Section>.Value %>"
    		        End Get
    		    End Property
    			</s>.Value

				msgClass &= MessageProperties(CInt(item.<MsgID>.Value))

				msgClass &= vbCrLf & "End Class"



				File.WriteAllText(Path.Combine(TargetPath & "\Messages", item.<MessageName>.Value & ".vb"), msgClass.NormalizeLineEndings)

			Next
		End Sub


		Sub ParseMessageContentsFile()
			For Each item In MsgContentsXml...<MsgContents>
				Dim o = New MessageContent()
				o.Indent = CInt(item.<Indent>.Value)
				o.Position = CInt(item.<Position>.Value)
				o.TagText = item.<TagText>.Value
				o.Description = item.<Description>.Value
				o.MsgID = CInt(item.<MsgID>.Value)
				MessageContents.Add(o)
			Next
		End Sub

		Class MessageContent
			Dim x As XElement = <a><Indent>0</Indent>
									<Position>3</Position>
									<TagText>28</TagText>
									<Reqd>1</Reqd>
									<Description>
									</Description>
									<MsgID>7</MsgID></a>
			Public Indent As Integer
			Public Position As Integer
			Public TagText As String
			Public MsgID As Integer
			Public Reqd As Boolean
			Private m_Description As String

			Public Property Description() As String
				Get
					Return m_Description
				End Get
				Set(ByVal value As String)
					If value IsNot Nothing Then m_Description = value.NormalizeLineEndings.Replace(vbCrLf, "")
				End Set
			End Property

			Public ReadOnly Property FieldName() As String
				Get
					If IsComponent Then
						Return TagText
					Else
						Return TagFieldMap(FieldNumber.Value)
					End If
				End Get
			End Property

			Public ReadOnly Property FieldNumber() As Integer?
				Get
					If Not IsComponent Then Return CInt(TagText)
				End Get
			End Property

			Public ReadOnly Property IsComponent() As Boolean
				Get
					Return Not IsNumeric(TagText)
				End Get
			End Property

		End Class


		Function MessageProperties(ByVal messageID As Integer) As String

			Dim query = (From item In MessageContents Where item.MsgID = messageID Order By item.Position).ToList
			Dim propertyBlock As New Text.StringBuilder

			Dim classDepth As New Stack(Of Integer)	'stores the indend level of the current class, not the number of nested classes!
			classDepth.Push(0)

			For index = 0 To query.Count - 1
				Dim item = query(index)

				Dim lastItem As MessageContent = Nothing
				If index > 0 Then
					lastItem = query(index - 1)
				End If

				Dim nextItem As MessageContent = Nothing
				If index < query.Count - 2 Then
					nextItem = query(index + 1)
				End If

				propertyBlock.AppendLine()
				If item.IsComponent Then
					propertyBlock.AppendLine("'Component: " & item.TagText)
				Else
					propertyBlock.AppendLine("'Field: " & item.FieldName & "(" & item.FieldNumber & ")")
				End If
				propertyBlock.AppendLine("'Position: " & item.Position)
				propertyBlock.AppendLine("'Indent: " & item.Indent)
				If item.Description <> "" Then propertyBlock.AppendLine("'Description: " & item.Description)
				propertyBlock.AppendLine()


				If nextItem IsNot Nothing AndAlso nextItem.Indent > item.Indent Then 'we are starting a repeating group

					Dim className As String
					Dim propertyName As String

					If nextItem.IsComponent Then
						className = nextItem.FieldName
						propertyName = nextItem.FieldName
					Else
						className = item.FieldName & "Block"
						propertyName = item.FieldName
					End If

					Dim variableName As String = "m_" & propertyName

					If nextItem.IsComponent Then
						'HACK! - for now we are not exporting components
						propertyBlock.AppendLine("' Private " & variableName & " As New List(Of " & className & ")")
						propertyBlock.AppendLine("' Public Readonly Property " & propertyName & " As List(Of " & className & ")")
						propertyBlock.AppendLine()
						'END HACK
					Else
						propertyBlock.AppendLine("Private " & variableName & " As New List(Of " & className & ")")
						propertyBlock.AppendLine("Public Readonly Property " & propertyName & " As List(Of " & className & ")")
						propertyBlock.AppendLine("Get")
						propertyBlock.AppendLine(" Return " & variableName)
						propertyBlock.AppendLine("End Get")
						propertyBlock.AppendLine("End Property ")
						propertyBlock.AppendLine()
					End If

					If Not nextItem.IsComponent Then
						classDepth.Push(nextItem.Indent) 'mark that we just started a new nested class
						propertyBlock.AppendLine()
						propertyBlock.AppendLine("Public Class " & className)
						propertyBlock.AppendLine()
					End If

					Continue For 'we are done with this field
				End If


				'End the nested class(s) if necessary
				Do While classDepth.Peek > item.Indent
					classDepth.Pop()
					propertyBlock.AppendLine("End Class")
				Loop


				If item.IsComponent Then

					'HACK! - for now we are not exporting components
					propertyBlock.AppendLine("' Property stuff goes here for " & item.FieldName)

				Else
					propertyBlock.AppendLine(TagPropertyMap(item.FieldNumber.Value))
				End If


			Next

			'End the nested class(s) if necessary
			Do While classDepth.Peek > 0
				classDepth.Pop()
				propertyBlock.AppendLine("End Class")
			Loop












			'For index = 0 To query.Count - 1
			'    Dim item = query(index)

			'    Dim currentIndent As Integer = CInt(item.<Indent>.Value)

			'    Dim lastItem As XElement = Nothing
			'    Dim lastIndent As Integer? = Nothing
			'    If index > 0 Then
			'        lastItem = query(index - 1)
			'        lastIndent = CInt(lastItem.<Indent>.Value)
			'    End If

			'    Dim nextItem As XElement = Nothing
			'    Dim nextIndent As Integer? = Nothing
			'    If index < query.Count - 2 Then
			'        nextItem = query(index + 1)
			'        nextIndent = CInt(nextItem.<Indent>.Value)
			'    End If


			'    If nextIndent = Nothing OrElse nextIndent = currentIndent Then 'We are in a normal field




			'    End If

			'    If nextIndent > currentIndent Then 'We are in a count field




			'    End If
















			'    propertyBlock.AppendLine()

			'    Dim tagText = item.<TagText>.Value
			'    Dim isComponenet As Boolean

			'    Dim tagName As String
			'    If IsNumeric(tagText) Then
			'        tagName = TagFieldMap(CInt(tagText))
			'        isComponenet = False
			'    Else
			'        tagName = tagText
			'        isComponenet = True
			'    End If



			'    If lastIndent > currentIndent Then
			'        'we just finished a class

			'        propertyBlock.AppendLine()
			'        propertyBlock.AppendLine("End Class")
			'        propertyBlock.AppendLine()

			'    End If

			'    If isComponenet Then
			'        propertyBlock.AppendLine("'Component: " & tagText)
			'        propertyBlock.AppendLine("'Position: " & item.<Position>.Value)
			'        If item.<Indent>.Value <> "0" Then propertyBlock.AppendLine("'Indent: " & item.<Indent>.Value)
			'        If item.<Description>.Value <> "" Then propertyBlock.AppendLine("'Desc: " & item.<Description>.Value.NormalizeLineEndings.Replace(vbCrLf, ""))



			'    Else

			'        If lastIndent < currentIndent Then
			'            'we are in a new class

			'            propertyBlock.AppendLine()
			'            propertyBlock.AppendLine("Class " & tagName)
			'            propertyBlock.AppendLine()

			'        End If

			'        propertyBlock.AppendLine("'Field: " & tagName & " (" & tagText & ")")
			'        propertyBlock.AppendLine("'Position: " & item.<Position>.Value)
			'        If item.<Indent>.Value <> "0" Then propertyBlock.AppendLine("'Indent: " & item.<Indent>.Value)
			'        If item.<Description>.Value <> "" Then propertyBlock.AppendLine("'Desc: " & item.<Description>.Value.NormalizeLineEndings.Replace(vbCrLf, ""))

			'        If item.<Reqd>.Value = "0" Then
			'            propertyBlock.AppendLine(TagPropertyMap(CInt(tagText)))
			'        Else
			'            propertyBlock.AppendLine(TagPropertyMapRequired(CInt(tagText)))
			'        End If

			'    End If




			'    If Not isComponenet Then
			'        lastIndent = currentIndent
			'    End If

			'Next

			Return propertyBlock.ToString
		End Function

	End Module


	Public MustInherit Class Message
		Public MustOverride ReadOnly Property MessageName() As String
		Public MustOverride ReadOnly Property MessageType() As String
		Public MustOverride ReadOnly Property MessageId() As Integer
		Public MustOverride ReadOnly Property Category() As String
		Public MustOverride ReadOnly Property Section() As String
	End Class










End Namespace
